package nl.weeaboo.sh.level.l99;

import static nl.weeaboo.sh.danmaku.SpellUtil.chain;
import static nl.weeaboo.sh.danmaku.SpellUtil.create;
import static nl.weeaboo.sh.danmaku.SpellUtil.distSq;
import static nl.weeaboo.sh.danmaku.SpellUtil.tAngle;
import static nl.weeaboo.sh.danmaku.SpellUtil.tAngleTo;
import static nl.weeaboo.sh.danmaku.SpellUtil.tDestroy;
import static nl.weeaboo.sh.danmaku.SpellUtil.tPos;
import static nl.weeaboo.sh.danmaku.SpellUtil.tPower;
import static nl.weeaboo.sh.danmaku.SpellUtil.tSolid;
import static nl.weeaboo.sh.danmaku.SpellUtil.tSpeed;
import static nl.weeaboo.sh.danmaku.SpellUtil.tVisible;
import static nl.weeaboo.sh.danmaku.SpellUtil.tWait;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.Random;

import nl.weeaboo.game.input.UserInput;
import nl.weeaboo.sh.Game;
import nl.weeaboo.sh.danmaku.ShotModel;
import nl.weeaboo.sh.danmaku.Spell;
import nl.weeaboo.sh.danmaku.SpellBook;
import nl.weeaboo.sh.danmaku.SpellUtil;
import nl.weeaboo.sh.danmaku.Universe;
import nl.weeaboo.sh.danmaku.UniverseAdapter;
import nl.weeaboo.sh.level.Level;
import nl.weeaboo.sh.objects.Boss;
import nl.weeaboo.sh.objects.Player;
import nl.weeaboo.sh.view.CharaImage;
import nl.weeaboo.sh.view.anim.Animation;

public class Cirno extends Boss {

	private int cooldown;
	private int moveFrame;
	private Point target;
	
	private Random random;
	private Animation a_idle;
	
	public Cirno(Game game, Level level) {
		super(game, level, game.getCharaImage("level99/boss-cirno.png#idle1"));
				
		a_idle = Animation.create(game, "level99/boss-cirno.png", true,
				"idle1", 6, "idle2", 6);
		anim = a_idle;
		
		random = new Random();
		
		nextSpellcard(spellcard + 1);
	}

	//Functions
	public void update(UserInput input, float dt) {
		UniverseAdapter ua = game.getLevel().getUniverseAdapter();

		if (ua != null) {		
			if (spellcard == 1) updatePhase1(dt);
			else if (spellcard == 2) updatePhase2(dt);
		}
		
		anim.request(a_idle);
		
		super.update(input, dt);
	}
	
	protected void updatePhase1(float dt) {
		Level level = (Level)game.getLevel();
		Player player = level.getPlayer();
		UniverseAdapter ua = level.getUniverseAdapter();
		Universe u = ua.getUniverse();

		cooldown--;
		moveFrame++;
		
		boolean fire = false;
		if (moveFrame >= 60) {
			int px = player.getX();
			int py = player.getY();
			target = new Point(px, py);

			toTarget(3f);
			
			if (moveFrame >= 180) {
				speedX = speedY = 0;				
				moveFrame = 0;
				fire = true;
			}
		}
		
		if (target != null && distSq(x, y, target.x, target.y) <= 5000f) {
			fire = true;
		}
		
		if (fire && cooldown <= 0) {			
			float angle = (dir < 0 ? 384 : 128);			
			int w2 = getImageBounds(dir < 0).width / 4;
			Point p = getSpawnPos();

			for (int n = 1; n <= 2; n++) {
				CharaImage i = game.getCharaImage("level99/boss-cirno.png#icicle" + n);

				create(u, i, 0, chain(
						tPos(p.x + (dir < 0 ? -w2-8 : w2), p.y),
						tPower(5),
						tAngle(angle),
						tSolid(true),
						tVisible(false),
						tWait(n == 1 ? 0 : 6),
						tVisible(true),
						tWait(n == 1 ? 6 : 60),
						tDestroy()));
			}
			
			moveFrame = 0;
			cooldown = 90;
			speedX = speedY = 0;
		}
	}

	protected void updatePhase2(float dt) {
		Level level = (Level)game.getLevel();
		UniverseAdapter ua = level.getUniverseAdapter();
		Universe u = ua.getUniverse();
		Rectangle r = ua.getBounds();

		moveFrame++;
		cooldown--;
		
		if (moveFrame == 120) {
			target = new Point(
					Math.round(r.x + (x > r.x + r.width/2 ? .25f : .75f) * r.width),
					r.y + r.height/2);

			cooldown = 0;
		} else if (moveFrame > 120 && moveFrame <= 10100) {
			toTarget(5f);
			
			if (distSq(x, y, target.x, target.y) < 1000f) {
				dir = (x > r.x + r.width/2 ? -1 : 1);
				if (cooldown <= 0) {
					CharaImage i = game.getCharaImage("level99/boss-cirno.png#snowball1");
					for (float n = 0; n < r.width; n += random.nextFloat() * 256f) {				
						create(u, i, 0, chain(
								tPower(3),
								tPos(n, r.height),
								tSpeed(2f + random.nextFloat() * 2f),
								tAngle(random.nextFloat()-.5f),
								new VWaitSpell(),
								tAngleTo(256, 5)));
					}
					
					cooldown = 10;
				}
				
				moveFrame = Math.max(moveFrame, 10000);
			}
		} else if (moveFrame > 10100) {
			moveFrame = 0;
		}
	}
	
	protected Point getSpawnPos() {
		UniverseAdapter ua = level.getUniverseAdapter();
		Rectangle r = ua.getBounds();
		return new Point(x-r.x+getImageBounds(dir==-1).width/2, y-r.y);
	}
	protected void toTarget(float s) {
		if (target == null) return;
		
		float angle = SpellUtil.angleTo(x, y, target.x, target.y);
		speedX = s * SpellUtil.fastSin(angle);
		speedY = s * -SpellUtil.fastCos(angle);
		
		if (distSq(x, y, target.x, target.y) < 1000f) {
			speedX = speedY = 0f;
		}
	}
	
	public void startSpell(int hp, int time) {
		super.startSpell(hp, time);
		
		moveFrame = cooldown = 0;
		target = null;		
	}

	protected boolean nextSpellcard(int newSpellcardNum) {
		spellcard = newSpellcardNum;

		switch (newSpellcardNum) {
		case 1: startSpell(50, 120); return true;		
		case 2: startSpell(100, 120); return true;		
		}
				
		return false;
	}
	
	//Getters
	
	//Setters
	
	//Inner Classes
	private static class VWaitSpell extends Spell {

		public Spell clone() {
			return new VWaitSpell();
		}
		public void step(Universe u, SpellBook sb, ShotModel s) {
			if (s.getY() < 32) finish();
		}								
		
	}
}
